package com.minotauro.bean.property;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sun.source.tree.MethodTree;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;

public class GetterSetterTreeVisitor extends TreePathScanner<Object, Trees> {

  private List<PropertyBean> propertyBeanList = new ArrayList<PropertyBean>();

  private Hashtable<String, MethodTree> hashTable = new Hashtable<String, MethodTree>();

  public static final String SETTER_GETTER_NAME = //
  "(set|get|is)([A-Z]{1})([a-zA-Z_0-9]+)";

  public static final int PREFIX_IS = 2;

  public static final int PREFIX_GET_SET = 3;

  public static final String IS = "is";

  public static final String GET = "get";

  public static final String SET = "set";

  public static Pattern patternMethodName = // 
  Pattern.compile(SETTER_GETTER_NAME);

  // --------------------------------------------------------------------------------

  public GetterSetterTreeVisitor() {
    // Empty
  }

  // --------------------------------------------------------------------------------

  public List<PropertyBean> getPropertyBeanList() {
    return propertyBeanList;
  }

  // --------------------------------------------------------------------------------

  private String getPropertyName(String methodName) {

    //Como mejorar esto?

    if (methodName.startsWith(IS)) {
      methodName = methodName.substring(PREFIX_IS);
    } else {
      methodName = methodName.substring(PREFIX_GET_SET);
    }

    char[] string = methodName.toCharArray();
    string[0] = Character.toLowerCase(string[0]);
    methodName = String.valueOf(string);

    return methodName;
  }

  // --------------------------------------------------------------------------------

  private Boolean isSetter(MethodTree tree) {

    if (tree.getName().toString().startsWith(SET)) {
      return true;
    }
    return false;
  }

  // --------------------------------------------------------------------------------

  private Boolean isGetter(MethodTree tree) {

    if (tree.getName().toString().startsWith(IS)) {
      return true;
    } else if (tree.getName().toString().startsWith(GET)) {
      return true;
    }
    return false;
  }

  // --------------------------------------------------------------------------------

  private String propertyNameToUpperCase(String propertyName) {
    StringBuffer ret = new StringBuffer();
    char prevChar = 'a';

    for (int i = 0; i < propertyName.length(); i++) {
      char currChar = propertyName.charAt(i);

      if (!Character.isUpperCase(prevChar) && Character.isUpperCase(currChar)
          && i > 0) {
        ret.append("_");
      }
      ret.append(Character.toUpperCase(currChar));
      prevChar = currChar;
    }

    return ret.toString();
  }

  // --------------------------------------------------------------------------------

  public boolean matchPattern(Pattern p, String s) {
    Matcher m = p.matcher(s);

    if (m.matches()) {
      return true;
    }

    return false;
  }

  // --------------------------------------------------------------------------------

  @Override
  public Object visitMethod(MethodTree tree, Trees trees) {

    if (tree.getReturnType() == null) {
      return super.visitMethod(tree, trees);
    }
    String methodName = tree.getName().toString();
    if (matchPattern(patternMethodName, methodName)) {
      String propertyName = getPropertyName(tree.getName().toString());
      if (hashTable.containsKey(propertyName)) {
        if (isSetter(tree)) {
          if (tree
              .getParameters()
              .toString()
              .startsWith(
                  hashTable.get(propertyName).getReturnType().toString())) {
            PropertyBean propertyBean = new PropertyBean();
            propertyBean.propertyName = propertyNameToUpperCase(propertyName);
            propertyBean.propertyValue = propertyName;
            propertyBeanList.add(propertyBean);
          }
        } else if (isGetter(tree)) {

          if (hashTable.get(propertyName).getParameters().toString()
              .startsWith(tree.getReturnType().toString())) {
            PropertyBean propertyBean = new PropertyBean();
            propertyBean.propertyName = propertyNameToUpperCase(propertyName);
            propertyBean.propertyValue = propertyName;
            propertyBeanList.add(propertyBean);
          }
        }
      } else {
        hashTable.put(propertyName, tree);
      }
    }
    return super.visitMethod(tree, trees);
  }
}